package base.widgets;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.redr.canvas.OSPath;
import org.redr.canvas.RRW;
import org.redr.canvas.RedRApplication;
import org.redr.widgetGUI.core.CommitButton;
import org.redr.widgetGUI.core.LineEdit;
import org.redr.widgetGUI.core.ListBox;
import org.redr.widgetGUI.core.RadioButtons;
import org.redr.widgetGUI.core.SpinBox;
import org.redr.widgetGUI.core.TextEdit;
import org.redr.widgetGUI.core.WidgetBox;
import org.redr.widgetGUI.settings.WidgetSettings;

import base.signals.RDataFrameInput;
import base.signals.RDataFrameOutput;

import com.trolltech.qt.core.Qt;
import com.trolltech.qt.gui.QAbstractItemView;

public class Apply extends RRW{
	public static final String name = "Apply";
	public static final String summary = "Perform an apply.";
	public static final String details = "Apply a function across a data frame or matrix..";
	public static final String icon = OSPath.join(RedRApplication.parentDir, "coreIcons", "default.png").getAbsolutePath();
	private int numDims;
	private Object data;
	private ListBox functions;
	private TextEdit functionText;
	private LineEdit parameters;
	private TextEdit customFunctionText;
	private RadioButtons demension;
	private SpinBox indexSpinBox;
	private CommitButton commit;
	private TextEdit dataTable;
	private TextEdit outputTable;
    
	public Apply(WidgetSettings ws) {
		super(ws);
	}

	@Override
	protected void initSignals() {
		// TODO Auto-generated method stub
	    this.addInput(new RDataFrameInput(this, "id1", _("X"), false));
	    this.addOutput(new RDataFrameOutput(this, "id1", _("Apply Data")));
	}

	@Override
	protected void initGUI() {
		WidgetBox area = new WidgetBox(this.gui, (WidgetSettings) settings.getSettings("area")
				.setSetting("orientation", "vertical")
				.setSetting("label", "Area Box"));       
			    
	    WidgetBox box = new WidgetBox(area, (WidgetSettings) settings.getSettings("box")
	    		.setSetting("label", "Box"));
	    box.widget().setMinimumWidth(200);
	    area.widget().layout().setAlignment(box.widget().layout(), Qt.AlignmentFlag.AlignLeft);
	    
	    this.functions =  new ListBox(box,  (WidgetSettings) settings.getSettings("functions")
	    		.setSetting("label", "Select Function"));
	    for (String s : new String[] {"mean", "median", "max","min","sum","log2", "log10", "var", "custom"}){
	    	this.functions.addItem(s, s);
	    }
	    this.functions.widget().setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection);
	    this.functions.widget().clicked.connect(this, "functionSelect");

	    // #redRGUI.base.separator(box,height=10)
	    this.functionText = new TextEdit(box, (WidgetSettings) settings.getSettings("functionText")
	    		.setSetting("label", "Function:")
	    		.setSetting("orientation", "vertical"));
	    
	    
	    
	    this.parameters = new LineEdit(box, (WidgetSettings) settings.getSettings("parameters")
	    		.setSetting("label", "Additional Parameters:")
	    		.setSetting("orientation", "vertical"));
	    		
	    this.customFunctionText = new TextEdit(box, (WidgetSettings) settings.getSettings("customFunctionText")
	    		.setSetting("label", "Custom Function")
	    		.setSetting("toolTip", "Takes the object data as it\'s parameters, this is the vector of data across the margin being used.  May cause errors in use that are not the fault of the widget developers.")
	    		.setSetting("orientation", "vertical"));
	    		
	    this.demension =  new RadioButtons(box, (WidgetSettings) settings.getSettings("demensions")
	    		.setSetting("label", "To:")
	    		.setSetting("orientation", "horizontal"));
	    
		for (String s : new String[] {_("All"), _("Rows"), _("Columns"),_("Other")}){
			this.demension.addButton(s, s);
		}
		this.demension.setChecked("Rows");
	    this.demension.widget().buttonClicked.connect(this, "demensionChanged()");
		
//		this.indexSpinBox = new SpinBox(this.demension, (WidgetSettings) settings.getSettings("indexSpinBox")
//				.setSetting("label", "Demension")
//				.setSetting("displayLabel", "false")
//				.setSetting("min", "1")
//				.setSetting("value", "1"));
//				
		this.indexSpinBox.widget().valueChanged.connect(this, "spinBoxChanged()");
		
		
	    WidgetBox buttonBox = new WidgetBox(box, (WidgetSettings) settings.getSettings("buttonBox")
	    		.setSetting("label", "Button Box")
	    		.setSetting("orientation", "horizontal"));
	    
	    this.commit = new CommitButton(buttonBox, (WidgetSettings) settings.getSettings("commit")
	    		.setSetting("label", _("Commit"))
	    		.setDefault("processOnInput", "true")
	    		.setDefault("processOnChange", "true"));
	    		
	    		
	    this.dataTable = new TextEdit(area, (WidgetSettings) settings.getSettings("dataTable")
	    		.setSetting("label", "Data Sample"));
	    		
	    this.outputTable = new TextEdit(area, (WidgetSettings) settings.getSettings("outputTable")
	    		.setSetting("label", "Results of Apply"));
	}

	@Override
	protected void dataInput(String id, Object data, String widgetId) {
		// TODO Auto-generated method stub
		if (id.equals("id1")){
			this.data = data;
			if (this.commit.processOnInput()){
				this.commitFunction();
			}
		}
	}

	private void commitFunction() {
		// TODO Auto-generated method stub
		String function = this.functionText.toPlainText();
	    String paramText = this.parameters.text();
	    if ((this.data == null) | (function == null) | (function.equals(""))) return;
		String[] params	=	StringUtils.split(paramText, ",");
	    
		if (!this.demension.checkedId().equals(_("All"))){
			List<String> injection	=	new ArrayList<String>();
			if (this.demension.checkedId().equals(_("Row"))){
				injection.add("MARGIN = 1");
			} else if (this.demension.checkedId().equals(_("Column"))){
				injection.add("MARGIN = 2");
			} else {
				injection.add(String.format("MARGIN = %s", this.indexSpinBox.widget().value()));
			}
			
			if (this.functions.selectedIds()[0].equals("custom")){
				try{
	                this.nullR(String.format("tempFun<-function(data){%s}", this.customFunctionText.toPlainText()));
	                injection.add("FUN=tempFun");
				} catch(Exception e) {
					e.printStackTrace();
					return;
				}
			} else {
	            injection.add("FUN="+this.functionText.toPlainText());
			}
		}
//			injection.addAll(params);
//	        injection.extend(params)
//	        
//	        inj = ','.join(injection)
//	        
//	        # try:
//	        this.R(this.Rvariables['apply']+'<- as.data.frame(apply(X='+unicode(this.data)+','+inj+'))', wantType = 'NoConversion')
//		}
//	        
//	        
//	    else:
//	        this.R('%s<-as.data.frame(%s(%s))' % (this.Rvariables['apply'], unicode(this.functionText.toPlainText()), this.data), wantType = redR.NOCONVERSION)
//	        
//	    newData = signals.base.RDataFrame( data = this.Rvariables['apply'])
//	    this.outputTable.setTable(newData)
//	    this.rSend("id0", newData)
	}

	@Override
	protected void initVariables() {
		// TODO Auto-generated method stub
		// this.setRvariableNames(["apply"])
		this.numDims = 2;
		this.data = null;
	}
	
	protected void dimensionChanged(){

	}
	
	protected void spinBoxChanged(){}
	/*

def dimensionChange(type):
    if type == 1:
        if this.demension.getChecked() ==_('Rows'):
            this.indexSpinBox.setValue(1)
        else:
            this.indexSpinBox.setValue(2)
    else:
        if this.indexSpinBox.value() == 1:
            this.demension.setChecked(_('Rows'))
        elif this.indexSpinBox.value() == 2:
            this.demension.setChecked(_('Columns'))
        else:
            this.demension.setChecked(_('Other'))
        
def processX( data):
    if data:
        this.data=data.getData()
        this.numDims = this.R('length(dim(%s))' % this.data)
        this.indexSpinBox.setMaximum(this.numDims)
        this.dataTable.captureOutput('head(%s)' % this.data)
        if this.commit.processOnInput():
            this.commitFunction()
    else:
        this.data=None
def functionSelect(this):
    selection = this.functions.currentSelection()
    f = selection[0].split('\n--')
    #print f
    this.functionText.setText(f[0])
    this.parameters.setText(', '.join(f[1:]))
    if this.commit.processOnChange():
        this.commitFunction()

	*/
}
